/*
        实现异步日志缓冲区

管理一个存放字符串数据的缓冲区 使用vector进行空间管理
写入位置的指针 应指向可写区域的起始位置 避免数据的写入覆盖
读取数据的指针 应指向可读区域的起始位置 
当读指针与写指针指向相同时候代表读取完毕

具体操作：向缓冲区写入数据 获取可读数据的起始位置接口 获取可读数据长度的接口 移动读写位置的接口 初始化缓冲区 提供交换缓冲区的操作（不交换空间数据 而是交换空间地址）
*/

#ifndef __M_BUFFER_H__
#define __M_BUFFER_H__
#include "util.hpp"
#include <vector>
#include <cassert>
namespace bitlog
{
    #define DEFAULT_BUFFER_SIZE (1 * 1024 * 1024)
    // 设置阈值
    #define THRESHOLD_BUFFER_SIZE (8 * 1024 * 1024)
    // 设置每次增长的量
    #define INCREMENT_BUFFER_SIZE (1 * 1024 * 1024)
    class Buffer
    {
    public:
        Buffer()
            :_buffer(DEFAULT_BUFFER_SIZE),
            _writer_idx(0),
            _reader_idx(0)
        {}
        // 向缓冲区写入数据
        void push(const char *data,size_t len)
        {
            // 先考虑缓冲区位置是否充足 不足的情况下 
            // 固定大小 则直接返回
            //if(len > writeAblesize()) return ;        
            // 动态空间 --扩容
            ensureEnoughSize(len);
            // 拷贝进缓冲区
            std::copy(data,data + len,&_buffer[_writer_idx]);
            // 将当前写入位置向后偏移
            moveWriter(len);
        }
        // 返回可读数据的长度
        size_t writeAblesize()
        {
            return (_buffer.size() - _writer_idx);
        }
        // 返回可读数据的起始位置
        const char* begin()
        {
            return &_buffer[_reader_idx];
        }
        // 返回可读数据的长度
        size_t readAblesize()
        {
            return (_writer_idx - _reader_idx);
        }
        // 对读指针进行向后偏移操作
        void moveReader(size_t len)
        {
            assert(len <= readAblesize());
            _reader_idx += len;
        }
        // 重置读写区 初始化缓冲区
        void reset()
        {
            _reader_idx = 0;
            _writer_idx = 0;
        }
        // 对Buffer进行交换操作
        void swap(Buffer &buffer)
        {
            _buffer.swap(buffer._buffer);
            std::swap(_reader_idx,buffer._reader_idx);
            std::swap(_writer_idx,buffer._writer_idx);
        }
        // 判断缓冲区是否为空
        bool empty()
        {
            return (_reader_idx == _writer_idx);
        }
    private:
        //对写指针进行向后偏移操作
        void moveWriter(size_t len)
        {   
            assert((len + _writer_idx) <= _buffer.size());
            _writer_idx += len;
        }
        //对空间进行扩容
        void ensureEnoughSize(size_t len)
        {
            if(len < writeAblesize()) return; // 不需要扩容
            size_t new_size = 0;
            if(_buffer.size() < THRESHOLD_BUFFER_SIZE)
            {
                // 小于阈值的情况下可以翻倍增长 考虑到翻倍也可能满足不了故加上len
                new_size = _buffer.size() * 2 + len; 
            }
            else
            {               
                // 大于阈值则线性增长 每次10MB
                new_size = _buffer.size() + INCREMENT_BUFFER_SIZE + len;
            }
            _buffer.resize(new_size);
        }

    private:
        std::vector<char> _buffer;
        size_t _reader_idx;  //可读数据区的指针----可用下标表示
        size_t _writer_idx;  //可写数据区的指针   
    };
}

#endif